// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) 2006 Microsoft Corporation. All rights reserved.

// Original code from the Microsoft Windows SDK for Windows Vista.

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Feeds.Interop;

// Provides feeds using the Vista RSS platform if available, but can fall
// back to using default feeds from resources.
public class FeedList
{
    private List<RssFeed> _rssFeeds;
    private int _currentFeedIndex;
    private int _currentItemIndex;
    private DateTime _lastRefresh;

    internal readonly static List<string> ImageExtensions = new List<string>(
        new string[] { "*.BMP", "*.GIF", "*.PNG", "*.JPG", "*.JPEG" });

    public FeedList()
    {
        this._lastRefresh = DateTime.MinValue;
        this._currentFeedIndex = -1;
        this._currentItemIndex = -1;
    }

    public void Refresh()
    {
        if (this._lastRefresh == DateTime.MinValue)
        {
            // Load the common feed list.
            Load();
            return;
        }

        // Exposes methods that provide access to the Common Feed List, 
        // which is a hierarchy of Really Simple Syndication (RSS) feeds 
        // to which the user is subscribed.
        FeedsManager fs = new FeedsManager();

        try
        {
            IFeedFolder folder = (IFeedFolder)fs.GetFolder("");
            foreach (IFeed feed in CommonFeedListUtils.LastWriteSince(folder, this._lastRefresh))
            {
                RssFeed rssFeed = null;
                try
                {
                    // This feed was updated or is new, let's get it.
                    rssFeed = RssFeed.FromApi(feed);
                }
                catch (System.Runtime.InteropServices.COMException ex)
                {
                    System.Diagnostics.Debug.Print("Failed to get RSS feed '{0}' from API; skipping feed. Error: {1} ", feed.Name, ex.ToString());
                    continue;  // Skip this feed.
                }

                // If the feed has no items with picture enclosures then skip it.
                if (rssFeed == null || rssFeed.Items.Count == 0)
                {
                    System.Diagnostics.Debug.Print("Feed '{0}' does not have any picture enclosures; skipping feed.", feed.Name);
                    continue;
                }

                // Before we add it let's see if we have an old version of the feed.
                int index = this._rssFeeds.FindIndex(delegate(RssFeed f) 
                    { return (f.Path == rssFeed.Path); });
                if (index == -1)
                {
                    // This must be a new feed, let's append it to the list.
                    this._rssFeeds.Add(rssFeed);
                }
                else
                {
                    // We have an existing feed with the same path. Let's insert it 
                    // where the previous feed is at.
                    this._rssFeeds.Insert(index, rssFeed);

                    // Remove previous feed.
                    this._rssFeeds.RemoveAt(index + 1);

                    // Assure that current indexes are not out of bounds.
                    ValidateIndexes();
                }
            }
        }
        finally
        {
            GC.Collect(); // Release all COM objects and their file handles.
            _lastRefresh = DateTime.Now;
        }
    }

    public void Load()
    {
        DateTime loadstart = DateTime.Now;
        List<RssFeed> newRssFeeds = new List<RssFeed>();

        try
        {
            FeedsManager fs = new FeedsManager();
            IFeedFolder folder = (IFeedFolder)fs.GetFolder("");
            foreach (IFeed feed in CommonFeedListUtils.CommonFeedList(folder))
            {
                System.Diagnostics.Debug.Print("Found feed {0} with {1} items.",
                    feed.Name, ((IFeedsEnum)feed.Items).Count);
                try
                {
                    RssFeed rssFeed = RssFeed.FromApi(feed);

                    // Only add this feed if it contains items
                    if (rssFeed != null)
                    {
                        System.Diagnostics.Debug.Print("Feed has {0} items with enclosures.", rssFeed.Items.Count); 
                        if (rssFeed.Items.Count > 0)
                            newRssFeeds.Add(rssFeed);
                    }
                    else
                        System.Diagnostics.Debug.Print("Feed is null.");
                }
                catch (System.Runtime.InteropServices.COMException ex)
                {
                    System.Diagnostics.Debug.Print("Failed to get RSS feed '{0}' from API; skipping feed. Error: {1} ", feed.Name, ex.ToString());
                    // Ignore exception, meaning ignore this feed and continue with next feed.
                }
            }
        }
        finally
        {
            // Collect garbage so that all the COM objects are released which 
            // closes the backing structured storage files.
            GC.Collect();
        }

        if (newRssFeeds.Count == 0)
        {
            // There were no suitable feeds, hence get default feeds from resources.
            System.Diagnostics.Debug.Print("There were no suitable feeds, hence get default feeds from resources.");
          
            RssFeed rssFeed = RssFeed.FromText(C4F.DevKit.RSS.ScreenSaverWPF.ResourcesWrapper.DefaultRSSText);
            newRssFeeds.Add(rssFeed);
        }

        this._rssFeeds = newRssFeeds;
        // reset current indexes
        this._currentFeedIndex = -1;
        this._currentItemIndex = -1;
        MoveNext();
        this._lastRefresh = loadstart;
    }

    public int Count { get { return _rssFeeds.Count; } }

    public RssFeed GetFeed(int index)
    {
        return this._rssFeeds[index];
    }

    public RssFeed CurrentFeed { get { return this._rssFeeds[this._currentFeedIndex]; } }
    public int CurrentFeedIndex { get { return this._currentFeedIndex; } }
    public RssItem CurrentItem { get { return this._rssFeeds[this._currentFeedIndex].Items[this._currentItemIndex]; } }
    public int CurrentItemIndex { get { return this._currentItemIndex; } }


    public void MoveNext()
    {
        if (this._rssFeeds == null || this._rssFeeds.Count == 0)
            return;


        // If we don't have a currentFeed then pick a feed and image
        if (this._currentFeedIndex == -1)
        {
            // Pick the first feed & image
            this._currentFeedIndex = 0;
            this._currentItemIndex = 0;
        }
        else
        {
            // Increment next item
            this._currentItemIndex++;
            ValidateIndexes();
        }
    }

    public void MovePrevious()
    {
        if (this._rssFeeds == null || this._rssFeeds.Count == 0)
            return;

        this._currentItemIndex--;

        if (this._currentItemIndex < 0)
        {
            // Return to the previous feed
            this._currentFeedIndex--;

            if (this._currentFeedIndex < 0)
                this._currentFeedIndex = this._rssFeeds.Count - 1;

            this._currentItemIndex = this._rssFeeds[this._currentFeedIndex].Items.Count - 1;
        }
    }

    private void ValidateIndexes()
    {
        // If we are at the end of the feed jump to the next feed
        if (this._currentItemIndex >= this._rssFeeds[this._currentFeedIndex].Items.Count)
        {
            this._currentItemIndex = 0;

            // We also need to go to the next feed
            this._currentFeedIndex++;

            // If we are at the end of the feeds jump to the first feed
            if (this._currentFeedIndex >= this._rssFeeds.Count)
            {
                this._currentFeedIndex = 0;
            }
        }
    }
}